local pi = math.acos(-1)
local sqrt2 = math.sqrt(2)
local os	= _G.os
local math  = _G.math
local floor = math.floor
local cos	= math.cos
local sin	= math.sin
local atan2	= math.atan2

function getTableCount(s)
	local count = 0
	if s == nil then return count end
	for __ in pairs(s) do
		count = count + 1
	end
	return count
end

function copyTable(s, t)
	for k, v in pairs(s) do
		if type(v) == "table" then
			t[k] = {}
			copyTable(v, t[k])
		else
			t[k] = v
		end
	end
end

function getBit(n, index)
	local div = 2 ^ index
	return (n - n % div) / div % 2
end

function setBit(n, index)
	local bit = getBit(n, index)
	if bit ~= 0 then
		assert()
	end
	return n + 2 ^ index
end

function hypot(a, b)
	return math.sqrt(a * a + b * b)
end

local out = {}
local out_len = 0
function printTable(tb, step)
	if not step then
		step = 0
		out_len = 0
	end
	for k, v in pairs(tb) do
		for i = 1, step do
			out_len = out_len + 1
			out[out_len] = "	"
		end

		if type(k) == "number" then
			out_len = out_len + 1
			out[out_len] = "["
		end

		out_len = out_len + 1
		out[out_len] = k

		if type(k) == "number" then
			out_len = out_len + 1
			out[out_len] = "]"
		end

		out_len = out_len + 1
		out[out_len] = "="

		if type(v) == "string" then
			out_len = out_len + 1
			out[out_len] = "\""
		end

		out_len = out_len + 1
		out[out_len] = type(v) == "table" and "" or v
		if type(v) == "boolean" then
			out[out_len] = tostring(v)
		end

		if type(v) == "string" then
			out_len = out_len + 1
			out[out_len] = "\""
		end

		out_len = out_len + 1
		out[out_len] = "\n"

		if type(v) == "table" then
			printTable(v, step + 1)
		end
	end
	if step == 0 then
		local str = table.concat(out, nil, 1, out_len)
		print(str)
		return str
	end
end

-- 2点距离
function dist(x,y,tx,ty)
	local vy = ty-y
	local vx = tx-x
	return math.sqrt(vy*vy + vx*vx)
end

-- XY不同速度换算2点距离
function dist2(x,y,tx,ty)
	local vy = ty-y
	local vx = tx-x
	local dy = vy*vy
	local dx = vx*vx
	return math.sqrt((2*dy+dx))
end

-- 2点角度
function getAngle(x,y,tx,ty)
	return -180*atan2(ty-y,tx-x)/pi
end

-- 目标点一定距离XY
function getTargetPoint(x,y,tx,ty,len)
	local v = hypot(x - tx, y - ty)
	if 1e-8 < v then 
		local vl = v - len
		return floor((tx - x) * vl / v + x), floor((ty - y) * vl / v + y)
	end
	local hudu = math.random() * 2 * pi
	return floor(x + cos(hudu) * len), floor(y + sin(hudu) * len)
end

-- 获取角度点
function getAnglePoint(dir,x,y,angle,radius)
	local way = (dir-2)*45
	local radian = (way-angle)/180*pi
	return floor(cos(radian)*radius + x),floor(sin(radian)*radius / sqrt2 + y)
end

function getAnglePoint2(x,y,tx,ty,radius)
	local radian = atan2(ty-y,tx-x)
	return floor(cos(radian)*radius + x),floor(sin(radian)*radius + y)
end

function getAnglePoint3(x,y,tx,ty,angle,radius)
	local radian = atan2(ty-y,tx-x)-(angle/180*pi)
	return floor(cos(radian)*radius + x),floor(sin(radian)*radius / sqrt2 + y)
end

-- 椭圆碰撞
function roundCollision(x,y,radius,tx,ty,targetRadius)
	local radiusWidth = radius+targetRadius
	local radiusHeight = radiusWidth*0.6	
	local dx = tx-x
	local dy = ty-y
	return dx*dx/(radiusWidth*radiusWidth)+dy*dy/(radiusHeight*radiusHeight)<=1
end
		
-- 矩形碰撞圆
function rectCollision(angle,rectCenterX,rectCenterY,rectX,rectY,rectWidth,rectHeight,circleX,circleY,circleRadius)
	local radian = angle*0.017453292519943295	
	local cos = cos(radian)
	local sin = sin(radian)
	
	local vx = circleX - rectCenterX
	local vy = circleY - rectCenterY
	local cx = cos * vx - sin * vy + rectCenterX;
	local cy = sin * vx + cos * vy + rectCenterY;

	local x, y;

	if cx < rectX then
		x = rectX;
	elseif cx > rectX + rectWidth then
		x = rectX + rectWidth;
	else
		x = cx;
	end

	if cy < rectY then
		y = rectY;
	elseif cy > rectY + rectHeight then
		y = rectY + rectHeight;
	else
		y = cy;
	end
	return dist(cx, cy, x, y) <= circleRadius
end

LN10 = LN10 or math.log(10)
function getResource(job,sex,v)
	if v < 0 then
		assert()
	end
	local len
	if v == 0 then
		len = 1
	else
		len = floor((math.log(v)+0.00000000001)/LN10)+1
	end
	return job * math.pow(10,len+1) + sex * math.pow(10,len) + v
end

local dir_x_y = {
	0, 1, 1,  1,  0, -1, -1, -1,
	-1, -1, 0, 1, 1, 1,  0,  -1
}

-- 扇型碰撞圆
function fanCollision(sx, sy, sd, tx, ty, tr, len, angle)
	local dx = tx - sx
	local dy = ty - sy
	if (len + tr) * (len + tr) < dx * dx + dy * dy then
		return
	end
	local back = tr / sin(angle)
	local dx, dy = dir_x_y[sd + 1], dir_x_y[sd + 9]
	sx = sx - dx * back
	sy = sy - dy * back
	tx = tx - sx
	ty = ty - sy
	return math.acos((dx * tx + dy * ty) / (hypot(dx, dy) * hypot(tx, ty))) < angle
end

-- 圆形路径 返回长度	isClockwise是否顺时针	
function setRoundPath(path,centerX,centerY,x,y,isClockwise)
	if centerX==x and centerY==y then
		return 0
	end
	local offsetAngle = getAngle(centerX,centerY/0.6,x,y/0.6)
	--print("offsetAngle",offsetAngle)
	local r = dist(centerX,centerY/0.6,x,y/0.6)
	local num =  math.min(floor(r/50*4),20)
	for i=1,num do
		local angle = 0
		if not isClockwise then
			angle = 360/num*(i-1) - offsetAngle
		else
			angle = 360/num*(num+1-i) - offsetAngle
		end
		
		local radian = angle/180*pi
		path[i*2-1] = floor(centerX + r*cos(radian))
		path[i*2] = floor(centerY + r*sin(radian)*0.6)
		if path[i*2-1] < 0 then
		    path[i*2-1] = 0
		end
		if path[i*2] < 0 then
		    path[i*2] = 0
		end
	end
	--printTable(path)
	return num
end

-- 判断是否同一天
function isSameDay(time1)
	if not time1 then
		return
	end
	local now = os.time()
	local tToday = os.date("%Y%m%d", now)
	local t1 = os.date("%Y%m%d", time1)
	if tToday ~= t1 then
		return
	end
	return now
end

-- 判断是否同一天
function isSameDay2(time1, time2)
	if time1 == nil or time2 == nil then
		return 
	end

	local t1 = os.date("%Y%m%d", time1)
	local t2 = os.date("%Y%m%d", time2)
	if t1 ~= t2 then
		return
	end
	return true
end

--距离今天结束还有多少秒
function remainDaySeconds()
  local tb = {}
  local nowDay = os.date("*t", os.time())
  tb.year = nowDay.year
  tb.month = nowDay.month
  tb.day = nowDay.day
  tb.hour = 23
  tb.min = 59
  tb.sec = 59
  local endTime = os.time(tb)
  return math.abs(endTime - os.time())
end

-- 判断传入的两个时间是否同一天
function isSameDayByTimes(time1,time2)
	if not time1 or not time2 then
		return
	end
	local t1 = os.date("%Y%m%d", time1)
	local t2 = os.date("%Y%m%d", time2)
	if t1 ~= t2 then
		return
	end
	return true
end

-- 是否同一个月
function isSameMonth(time)
	local now = os.date("*t")
	local d = os.date("*t",time)	
	return now.year==d.year and now.month==d.month
end

-- 判断传入时间点与当前时间相差多少天
local tb = {}
function diffDay(time)
	local d = os.date("*t",time)
	tb.year = d.year
	tb.month = d.month
	tb.day = d.day
	time = os.time(tb)
	local nowDay = os.date("*t", os.time())
	tb.year = nowDay.year
	tb.month = nowDay.month
	tb.day = nowDay.day
	local nowTime = os.time(tb)
	return math.ceil(math.abs(nowTime - time)/86400)
end

function diffDayByTimes(time1,time2)
	local t1 = os.date("*t",time1)
	tb.year = t1.year
	tb.month = t1.month
	tb.day = t1.day
	time1 = os.time(tb)
	local t2 = os.date("*t",time2)
	tb.year = t2.year
	tb.month = t2.month
	tb.day = t2.day
	time2 = os.time(tb)
	return math.ceil(os.difftime(time1,time2)/86400)
end

-- 获取本月有多少天
function getMonthDayNum()
	local currMonthDate = os.date("*t")
	tb.year = currMonthDate.year
	tb.month = currMonthDate.month
	tb.day = currMonthDate.day
	
	
	currMonthDate.day = 1
	tb.day = 1
	
	if tb.month<12 then	
		tb.month = tb.month + 1
	else
		tb.year = tb.year+1 
		tb.month = 1
	end
	
	local nextMonthFirstDayTime = os.time(tb)
	local currMonthTime = os.time(currMonthDate)
	
	return math.ceil(os.difftime(nextMonthFirstDayTime,currMonthTime)/86400)
end

-- 取时间间隔 s
function getInterval(time)
	if not time then
		return math.huge
	end
	local now = os.time()
	return now - time
end

-- check time
function checkTime(startTimeConf,endTimeConf)
	local nowDate = os.date("*t")
	local nowMin = nowDate.hour * 60 + nowDate.min
	
	local startMin = startTimeConf.hour * 60 + startTimeConf.min 
	local endMin = endTimeConf.hour * 60 + endTimeConf.min
	
	if nowMin >= startMin and nowMin < endMin then
		return true
	end 
end

-- 检查传入时间，是否经过resetTime时间点;
function isTimeOver(time,resetTime)
	
	if not time or not resetTime then
		return
	end
	
	local nowTime = os.time()
	local nowDay = os.date("%d", nowTime) + 0
	local nowHour = os.date("%H", nowTime) + 0
	
	local getDay = os.date("%d", time) + 0
	local getHour = os.date("%H", time) + 0
	
	local dirty = false
	if nowDay == getDay then
		if getHour < resetTime and nowHour >= resetTime then
			dirty = true
		end
	elseif nowDay == getDay + 1 then
		if nowHour >= resetTime then
			dirty = true	
		end
	else
		dirty = true
	end
	return dirty
end

-- 取本周开始时间 周一凌晨
tmpDate = {} or tmpDate
function getWeekStartTime(time)
	local d = os.date("*t",time)
	tmpDate.year = d.year
	tmpDate.month = d.month
	tmpDate.hour = 0
	tmpDate.min = 0
	tmpDate.sec = 0
	local day = nil
	if d.wday == 1 then
		day = 6
	else
		day = d.wday - 2
	end
	tmpDate.day = d.day - day
	return os.time(tmpDate)
end

-- 判断传入时间点，是否同周
function isSameWeek(time1,time2)
	if not time1 or not time2 then
		return
	end
	return getWeekStartTime(time1) == getWeekStartTime(time2)
end

-- 星期中第几天的数字表示 1（表示星期天）到 7（表示星期六） 
function getWeekDay( time )
	local time = time or os.time()
	local d = os.date("*t",time)
	return d.wday
end

function split(str, split_char)
    local t = {}
    while string.len(str)>0 do
        local pos = string.find(str, split_char);
        if (not pos) then
            t[#t + 1] = str
            break
        end
        local sub_str = string.sub(str, 1, pos - 1)
        t[#t + 1] = sub_str
        str = string.sub(str, pos + 1, #str)
    end
    return t
end

-- 根据KEY从小到大排序
function pairsByKeys(t)
	local a = {}
	for n in pairs(t) do
		a[#a+1] = n
	end
	table.sort(a)
	local i = 0
	return function()
	i = i + 1
	return a[i], t[a[i]]
	end
end 

function cmptb(a, b)
	for k, v in pairs(a) do
		if type(v) == "table" then
			if type(b[k]) ~= "table" then
				print(k)
				return
			end
			if not cmptb(v, b[k]) then
				print(k)
				return
			end
		else
			if b[k] ~= v and k ~= "now" and k ~= "uid" then
				print(k)
				return
			end
		end
	end
	for k, v in pairs(b) do
		if type(v) == "table" then
			if type(a[k]) ~= "table" then
				print(k)
				return
			end
			if not cmptb(v, a[k]) then
				print(k)
				return
			end
		else
			if a[k] ~= v and k ~= "now" and k ~= "uid" then
				print(k)
				return
			end
		end
	end
	return true
end

function getDir(dx, dy)
	return floor(( atan2(dy, dx) + pi * 2.625) * 4 / pi) % 8;
end

function tableIsEmpty(tb)
	return _G.next(tb) == nil
end

SPECIAL_AREA_NAME = {
	"北京", "深圳", "上海"
}

function isSpecialIP(areaStr)
	if areaStr == nil or areaStr == "" then return end
	
	for i = 1, #SPECIAL_AREA_NAME do
		if string.find(areaStr, SPECIAL_AREA_NAME[i]) ~= nil then
			return true
		end
	end
end
